#ifndef AAF44F45_375C_407F_93CB_CF9AC4AA175E
#define AAF44F45_375C_407F_93CB_CF9AC4AA175E

/*
    完成日志器模块：
    1、抽象日志器基类
    2、派生出不同的子类（同步日志器类 & 异步日志器类）
*/

#include "util.hpp"
#include "format.hpp"
#include "level.hpp"
#include "message.hpp"
#include "sink.hpp"
#include "looper.hpp"
#include <atomic>
#include <mutex>
#include <stdarg.h>
#include <sstream>
#include <memory>
#include <unordered_map>

namespace mian_yang
{
    class Logger
    {
    public:
        using ptr = std::shared_ptr<Logger>;

        Logger(const std::string &logger_name, LogLevel::value lv, Formatter::ptr &formatter, std::vector<LogSink::ptr> &sinks)
            : _logger_name(logger_name), _limit_level(lv), _formatter(formatter), _sinks(sinks)
        {
        }

        const std::string &Getname()
        {
            return _logger_name;
        }

        /*完成构造日志消息对象过程并进行格式化， 得到格式化后的日志消息字符串--然后进行输出*/
        void debug(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 通过输入的参数构造出一个日志消息对象， 进行日志的格式化，最终落地
            // 1、判断当前的日志是否达到了输出等级
            if (LogLevel::value::DEBUG < _limit_level)
            {
                // 不可以输出， 直接返回
                return;
            }

            // 2、对fmt格式化字符串和不定参进行字符串组织， 得到的日志消息的字符串
            va_list ap;
            va_start(ap, fmt);
            char *res; // 对字符串进行格式化组织， 组织后得到的字符串都在这个里面
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret < 0)
            {
                std::cout << "vasprintf failed!\n"
                          << std::endl;
                return;
            }
            va_end(ap); // 将ap指针格式化到最后
            serialize(file, line, res, LogLevel::value::DEBUG);
        }
        void info(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            if (LogLevel::value::INFO < _limit_level)
            {
                return;
            }

            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret < 0)
            {
                std::cout << "vasprintf failed!\n"
                          << std::endl;
                return;
            }
            va_end(ap);
            serialize(file, line, res, LogLevel::value::INFO);
        }
        void warn(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            if (LogLevel::value::WARN < _limit_level)
            {
                return;
            }

            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret < 0)
            {
                std::cout << "vasprintf failed!\n"
                          << std::endl;
                return;
            }
            va_end(ap);
            serialize(file, line, res, LogLevel::value::WARN);
        }
        void error(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            if (LogLevel::value::ERROR < _limit_level)
            {
                return;
            }

            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret < 0)
            {
                std::cout << "vasprintf failed!\n"
                          << std::endl;
                return;
            }
            va_end(ap);
            serialize(file, line, res, LogLevel::value::ERROR);
        }
        void fatal(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            if (LogLevel::value::FATAL < _limit_level)
            {
                return;
            }

            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret < 0)
            {
                std::cout << "vasprintf failed!\n"
                          << std::endl;
                return;
            }
            va_end(ap);
            serialize(file, line, res, LogLevel::value::FATAL);
        }

    protected:
        /*封装接口，减少代码冗余/ 将第3， 4， 5步封装起来*/
        void serialize(const std::string file, size_t line, char *res, LogLevel::value level)
        {
            // 3、构造LogMsg对象
            LogMsg msg(file, line, _logger_name, res, level); // 这里的res是格式化字符串,也就是我们想要打印的消息
            // 4、通过格式化工具对LogMsg进行格式化， 得到格式化后的日志字符串
            std::stringstream ss;
            _formatter->format(ss, msg); // 这里应该发生拷贝，构造的
            std::string str = ss.str();
            // 5、进行日志落地
            log(str.c_str(), str.size());
            // finally 释放res
            free(res);
        }

        /*抽象接口完成实际的落地输出--不同的日志器会有不同的实际落地方式*/
        virtual void log(const char *data, size_t len) = 0;

    protected:
        std::mutex _mutex;                         // 日志落地要保证线程安全问题， 用到互斥锁
        std::string _logger_name;                  // 日志器名称
        std::atomic<LogLevel::value> _limit_level; // 日志等级检查
        Formatter::ptr _formatter;                 // 格式化器
        std::vector<LogSink::ptr> _sinks;          // 落地对象的保存
    };

    /*同步日志器， 是将日志直接通过落地模块句柄进行过日志落地*/
    class SyncLogger : public Logger
    {
    public:
        SyncLogger(const std::string &logger_name,
                   LogLevel::value lv,
                   Formatter::ptr &formatter,
                   std::vector<LogSink::ptr> &sinks)
            : Logger(logger_name, lv, formatter, sinks)
        {
        }

    protected:
        void log(const char *data, size_t len)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if (_sinks.empty())
                return;
            for (auto &sink : _sinks)
            {
                sink->log(data, len);
            }
        }
    };

    class AsyncLogger : public Logger
    {
    public:
        AsyncLogger(const std::string &logger_name,
                    LogLevel::value lv,
                    Formatter::ptr &formatter,
                    std::vector<LogSink::ptr> &sinks,
                    AsyncType _looper_type)
            : Logger(logger_name, lv, formatter, sinks),
              _looper(std::make_shared<AsyncLooper>(std::bind(&AsyncLogger::realLog,
                                                              this,
                                                              std::placeholders::_1),
                                                    _looper_type))
        {
        }

        void log(const char *data, size_t len) // 将数据写入缓冲区
        {
            _looper->push(data, len);
        }

        // 将缓冲区的数据进行实际落地
        void realLog(Buffer &buf)
        {
            if (_sinks.empty())
                return;
            for (auto &sink : _sinks)
            {
                sink->log(buf.begin(), buf.readAbleSize());
            }
        }

    private:
        AsyncLooper::ptr _looper;
    };

    /*使用建造者模式建造日志器， 不要让用户直接去构造日志器， 减少用户的使用复杂度。
        1、抽象一个日志器建造者类（完成日志器对象所需零部件的构建 + 日志器的构建）
            1、设置日志器类型
            2、将不同类型日志器的创建， 放到同一个日志器建造者类中完成。
        2、派生出具体的建造者类 -- 局部日志器建造者（用户创建一个日志器自己使用） & 全局日志器建造者（添加了全局单例管理器之后
        ，将日志器添加全局管理）
    */
    enum class LoggerType
    {
        LOGGER_SYNC, // 同步日志器，
        LOGGER_ASYNC // 异步日志器
    };

    class LoggerBuilder
    {
    public:
        LoggerBuilder()
            : _logger_type(LoggerType::LOGGER_SYNC),
              _limit_level(LogLevel::value::DEBUG),
              _looper_type(AsyncType::ASYNC_SAFE)
        {
        }

        void buildEnableUnSageAsync()
        {
            _looper_type = AsyncType::ASYNC_UNSAFE;
        }

        void buildLoggerType(LoggerType type)
        {
            _logger_type = type;
        }

        void buildLoggerName(const std::string &name)
        {
            _logger_name = name;
        }

        void buildLoggerLevel(LogLevel::value level)
        {
            _limit_level = level;
        }

        /*构造一个格式化器*/
        void buildFormatter(const std::string &pattern)
        {
            _formatter = std::make_shared<Formatter>(pattern); // make_shared创建一个智能指针， 参数是原类型的参数。
        }
        void buildFormatter()
        {
            _formatter = std::make_shared<Formatter>(); // make_shared创建一个智能指针， 参数是原类型的参数。
        }

        /*落地器*/
        template <class SinkType, typename... Args>
        void buildSink(Args &&...args) // 完成不同落地器的创建， 完成之后添加到vector里面。
        {
            LogSink::ptr psink = SinkFactory<SinkType>::create(std::forward<Args>(args)...);
            _sinks.push_back(psink);
        }
        virtual Logger::ptr build() = 0; // 建造日志器

    protected:
        AsyncType _looper_type;                    // 如果是异步日志器， 那么异步日志器的安全类型
        LoggerType _logger_type;                   // 日志器类型
        std::mutex _mutex;                         // 日志落地要保证线程安全问题， 用到互斥锁
        std::string _logger_name;                  // 日志器名称
        std::atomic<LogLevel::value> _limit_level; // 日志等级检查
        Formatter::ptr _formatter;                 // 格式化器
        std::vector<LogSink::ptr> _sinks;          // 落地对象的保存
    };

    class LocallLoggerBuilder : public LoggerBuilder
    {
    public:
        Logger::ptr build() override
        {
            assert(!_logger_name.empty());   /*必须有日志器名称*/
            if (_formatter.get() == nullptr) /*智能指针的get接口获取原生指针*/
            {
                _formatter = std::make_shared<Formatter>();
            }
            if (_sinks.empty()) /*此时没有落地器*/
            {
                buildSink<StdoutSink>();
            }

            if (_logger_type == LoggerType::LOGGER_ASYNC) /*异步日志器*/
            {

                return std::make_shared<AsyncLogger>(_logger_name, _limit_level, _formatter, _sinks, _looper_type);
            }
            else
            {
                return std::make_shared<SyncLogger>(_logger_name, _limit_level, _formatter, _sinks);
            }
        }
    };

    class LoggerManager
    {
    public:
        static LoggerManager &GetInstance()
        {
            static LoggerManager eton;
            return eton;
        }
        void addLogger(Logger::ptr &logger)
        {
            /*检验add是否存在，如果已经存在了， 就return，不需要重复添加*/
            if (hasLogger(logger->Getname()))
                return;
            std::unique_lock<std::mutex> lock(_mutex);
            _loggers.insert(std::make_pair(logger->Getname(), logger));
        }

        bool hasLogger(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex); // 加锁
            auto it = _loggers.find(name);
            if (it == _loggers.end())
            {
                return false;
            }
            return true;
        }

        Logger::ptr getLogger(const std::string &name)
        {
            /*获取日志器*/
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _loggers.find(name);
            if (it == _loggers.end())
            {
                return Logger::ptr();
            }
            return it->second;
        }

        Logger::ptr rootLogger()
        {
            return _root_logger;
        }

    private:
        LoggerManager()
        {
            std::unique_ptr<mian_yang::LoggerBuilder> builder(new mian_yang::LocallLoggerBuilder());
            builder->buildLoggerName("root");
            _root_logger = builder->build();
            _loggers.insert(std::make_shared("root", _root_logger));
        }

    private:
        std::mutex _mutex;
        Logger::ptr _root_logger;                              // 默认日志器
        std::unordered_map<std::string, Logger::ptr> _loggers; // 日志器名称映射日志器
    };

    /*设计一个全局日志器的建造者 -- 在局部的基础上增加了一个功能：将日志器添加到单例对象中*/

    class GlobalLoggerBuilder : public LoggerBuilder
    {
        Logger::ptr build() override
        {
            assert(!_logger_name.empty());   /*必须有日志器名称*/
            if (_formatter.get() == nullptr) /*智能指针的get接口获取原生指针*/
            {
                _formatter = std::make_shared<Formatter>();
            }
            if (_sinks.empty()) /*此时没有落地器*/
            {
                buildSink<StdoutSink>();
            }

            Logger::ptr logger;

            if (_logger_type == LoggerType::LOGGER_ASYNC) /*异步日志器*/
            {

                logger = std::make_shared<AsyncLogger>(_logger_name, _limit_level, _formatter, _sinks, _looper_type);
            }
            else
            {
                logger = std::make_shared<SyncLogger>(_logger_name, _limit_level, _formatter, _sinks);
            }
            LoggerManager::GetInstance().addLogger(logger);
            return logger;
        }
    };

    void Test1Logger()
    {
        const std::string Logger_name = "sync_logger";                              // 定义日志器名称
        mian_yang::LogLevel::value Logger_level = mian_yang::LogLevel::value::WARN; // 设置限制等级为WARN
        mian_yang::Formatter::ptr fmt(new Formatter());                             // 日志格式设置

        /*这里创建三种落地方式， 其实就是多态的应用。 这里都是使用LogSink类型的智能指针指向子类的对象， 调用的是子类重写的虚函数*/
        mian_yang::StdoutSink::ptr StdLsp = mian_yang::SinkFactory<StdoutSink>::create();
        mian_yang::FileSink::ptr FileLsp = mian_yang::SinkFactory<FileSink>::create("./logfile/test.log/file.log");
        mian_yang::RollSink::ptr RollLsp = mian_yang::SinkFactory<RollSink>::create("./logfile/test.log/roll-", 1024 * 1024);

        std::vector<mian_yang::LogSink::ptr> sinks = {RollLsp, FileLsp, StdLsp};

        // 然后创建日志器， 将这些信息整合起来//这里是智能指针， 那么就是使用new对象初始化。没有问题，
        mian_yang::Logger::ptr Logger_ptr(new mian_yang::SyncLogger(Logger_name, Logger_level, fmt, sinks));

        int cnt = 0;
        while (cnt <= 5 * 10000)
        {
            Logger_ptr->fatal(__FILE__, __LINE__, "日志消息——%d", cnt);
            cnt++;
        }
    }

    void Test2Logger()
    {
        std::unique_ptr<LoggerBuilder> Lgbder(new LocallLoggerBuilder()); /*不允许抽象类型创建对象， 那么可以使用抽象指针。*/
        Lgbder->buildLoggerName("sync_logger");
        Lgbder->buildLoggerLevel(mian_yang::LogLevel::value::WARN);
        Lgbder->buildFormatter();
        Lgbder->buildLoggerType(LoggerType::LOGGER_SYNC);
        Lgbder->buildSink<FileSink>("./logfile/test.log/file.log");
        Lgbder->buildSink<RollSink>("./logfile/test.log/roll-", 1024 * 1024);
        Logger::ptr Logger_ptr = Lgbder->build();

        int cnt = 0;
        while (cnt <= 2 * 10000)
        {
            Logger_ptr->fatal(__FILE__, __LINE__, "日志消息——%d", cnt);
            cnt++;
        }
    }

    void Test3Logger()
    {
        std::unique_ptr<LoggerBuilder> Lgbder(new LocallLoggerBuilder()); /*不允许抽象类型创建对象， 那么可以使用抽象指针。*/
        Lgbder->buildLoggerName("async_logger");
        Lgbder->buildLoggerLevel(mian_yang::LogLevel::value::WARN);
        Lgbder->buildFormatter();
        Lgbder->buildLoggerType(LoggerType::LOGGER_ASYNC);
        Lgbder->buildSink<FileSink>("./logfile/test.log/file.log");
        Lgbder->buildSink<RollSink>("./logfile/test.log/roll-", 1024 * 1024);
        Logger::ptr Logger_ptr = Lgbder->build();

        int cnt = 0;
        while (cnt <= 50 * 10000)
        {
            Logger_ptr->fatal(__FILE__, __LINE__, "日志消息——%d", cnt);
            cnt++;
        }
    }
    void _Test4Logger()
    {
        mian_yang::Logger::ptr Logger_ptr = LoggerManager::GetInstance().getLogger("async_Logger");
        int cnt = 0;
        while (cnt <= 50 * 10000)
        {
            Logger_ptr->fatal(__FILE__, __LINE__, "日志消息——%d", cnt);
            cnt++;
        }
    }

    void Test4Logger()
    {
        std::unique_ptr<LoggerBuilder> Lgbder(new GlobalLoggerBuilder()); /*不允许抽象类型创建对象， 那么可以使用抽象指针。*/
        Lgbder->buildLoggerName("async_logger");
        Lgbder->buildLoggerLevel(mian_yang::LogLevel::value::WARN);
        Lgbder->buildFormatter();
        Lgbder->buildLoggerType(LoggerType::LOGGER_ASYNC);
        Lgbder->buildSink<FileSink>("./logfile/test.log/file.log");
        Lgbder->buildSink<RollSink>("./logfile/test.log/roll-", 1024 * 1024);
        Lgbder->build();
        _Test4Logger();
    }

}

#endif /* AAF44F45_375C_407F_93CB_CF9AC4AA175E */
